/** \file    smash_segm.h
  * \brief   Splits (smashs) given segmentation over the given boundaries and writes subsegments 
  *		back into index map, guarantying uniqueness of theirs indexes.
  * \date    2001, 2002
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/smash_segm.h,v 1.1 2004/02/04 14:43:24 cscom1r4 Exp $
  */

#ifndef _smash_segm_h_
#define _smash_segm_h_

#include "boundmap.h"
#include "segmcomb.h"
#include "segmbasic.h"

namespace img {

///checks that two pixels are from same source segment and not divided by a bound
template <class R>
class bound_checker
{
public:
	bound_checker(R &r, const boundmap &b) : _r(r), _b(b) {}
	bool top(size_t x, size_t y) const
		{ return _r(x,y-1) == _r(x,y) && !_b.vert_dividual(x, y-1); }
	bool left(size_t x, size_t y) const
		{ return _r(x-1,y) == _r(x,y) && !_b.horiz_dividual(y, x-1); }
	bool top_left(size_t x, size_t y) const
		{ return _r(x-1,y-1) == _r(x,y) && !_b.any_cut(x,y); }
	bool top_right(size_t x, size_t y) const
		{ return _r(x+1,y-1) == _r(x,y) && !_b.any_cut(x+1,y); }
private:
	R &_r;
	const boundmap &_b;
};

class bound_checker0
{
public:
	bound_checker0(const boundmap &b) : _b(b) {}
	bool top(size_t x, size_t y) const
		{ return !_b.vert_dividual(x, y-1); }
	bool left(size_t x, size_t y) const
		{ return !_b.horiz_dividual(y, x-1); }
	bool top_left(size_t x, size_t y) const
		{ return !_b.any_cut(x,y); }
	bool top_right(size_t x, size_t y) const
		{ return !_b.any_cut(x+1,y); }
private:
	const boundmap &_b;
};

///\return formed number of segments
template <class R, class RI>
size_t smash_segm(const R& segm, const boundmap &smash_bounds, RI& index_map,
  	size_t separable_sg_size = 1)	///< subsegments with size less than it should not appear
{
	size_t w = segm.width(), h = segm.height();
	assert(index_map.width() == w && index_map.height() == h);

	typedef merge_patch<> piece; //element of segment
	std::vector<piece> piece_vector;

	segmbasic4(index_map, piece_vector, bound_checker<const R>(segm, smash_bounds));

	//some passes here
	if (separable_sg_size > 1)
		vmerge_small(
			segm,
			index_map,
			piece_vector,
			separable_sg_size);

	rewrite(index_map, piece_vector);

	return xtd::root_count(piece_vector);
}

///\return formed number of segments
template <class RI>
size_t smash_segm(const boundmap &smash_bounds, RI& index_map)
{
	size_t w = index_map.width(), h = index_map.height();

	typedef merge_patch<> piece; //element of segment
	std::vector<piece> piece_vector;

	segmbasic4(index_map, piece_vector, bound_checker0(smash_bounds));

	rewrite(index_map, piece_vector);

	return xtd::root_count(piece_vector);
}

} //namespace img

#endif //_smash_segm_h_
